﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using YArchitech.DataModel;
using YArchitech.LIB;
using YArchitech.MEP;
using YArchitech.Revit;
using YArchitech.Revit.Electric.Common;
using HYRElectric.WirePlace;

namespace HYRElectric.Equipment
{
	public class FireDetectorLayout
	{
		public FireDetectorLayout(UIDocument uiDocument, Document document)
		{
			this.uiDoc = uiDocument;
			this.doc = document;
		}

		public bool Layout()
		{
			FireDetectorLayoutForm fireDetectorLayoutForm = new FireDetectorLayoutForm();
			if (fireDetectorLayoutForm.ShowDialog() == DialogResult.OK)
			{
				FireDetectorType detectorType = fireDetectorLayoutForm.DetectorType;
				int layoutWay = fireDetectorLayoutForm.LayoutWay;
				this.familyFile = this.GetFamilyFile(detectorType);
                this.familySymbol = this.GetFamilySymbol(this.familyFile, BuiltInCategory.OST_FireAlarmDevices);
				if (this.familySymbol == null)
				{
					return false;
				}
				if (layoutWay == 0)
				{
					this.RandomLayout(detectorType);
				}
				else
				{
					this.RectLayout(detectorType);
				}
			}
			return true;
		}

		private string GetFamilyFile(FireDetectorType type)
		{
			string result = string.Empty;
			if (type == FireDetectorType.Detector_Thermal)
			{
				result = Path.Combine(Product.FamilyLocation, RevitVersion.GetVersionNumber(this.doc), "FireDetector", "感温火灾探测器_吸顶.rfa");
			}
			else
			{
				result = Path.Combine(Product.FamilyLocation, RevitVersion.GetVersionNumber(this.doc), "FireDetector", "感烟火灾探测器_吸顶.rfa");
			}
			return result;
		}

		private FamilySymbol GetFamilySymbol(string familyFile, BuiltInCategory builtInCategory)
		{
			FamilySymbol result = null;
			Family family = null;
			if (this.doc == null || !File.Exists(familyFile))
			{
				return null;
			}
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(familyFile);
			Transaction transaction = null;
			try
			{
				foreach (Element element in YJKElementFilter.GetElementByCategory(this.doc, typeof(FamilySymbol), builtInCategory))
				{
					FamilySymbol familySymbol = element as FamilySymbol;
					if (familySymbol.Family.Name == fileNameWithoutExtension)
					{
						return familySymbol;
					}
				}
				transaction = new Transaction(this.doc, "LoadFamily");
				transaction.Start();
				this.doc.LoadFamily(familyFile, out family);
				transaction.Commit();
			}
			catch (Exception)
			{
			}
			finally
			{
                if (transaction != null && transaction.GetStatus() != TransactionStatus.Committed)
				{
					transaction.RollBack();
				}
			}
			if (family != null)
			{
				using (List<FamilySymbol>.Enumerator enumerator2 = family.GetSymbols().GetEnumerator())
				{
					if (enumerator2.MoveNext())
					{
						result = enumerator2.Current;
					}
				}
			}
			return result;
		}

		private void SetParametersValue(Element element, double level, double radius)
		{
			if (element == null)
			{
				return;
			}
			ElementParameter.SetParameterValueEx(element, "安装高度", level, (Autodesk.Revit.DB.ParameterType)3);
			ElementParameter.SetParameterValueEx(element, "保护半径", radius, (Autodesk.Revit.DB.ParameterType)3);
			string text = Path.GetFileNameWithoutExtension(this.familyFile);
			text = text.Substring(3);
			ElementParameter.SetParameterValueEx(element, "名称", text, (Autodesk.Revit.DB.ParameterType)1);
		}

		private void RandomLayout(FireDetectorType type)
		{
			FireRandomLayoutForm fireRandomLayoutForm = new FireRandomLayoutForm(type);
			fireRandomLayoutForm.Show(WindowHelper.HWndRevit);
			WindowHelper.SendMessageToWndRevit();
			Transaction transaction = null;
			try
			{
                List<ElementId> elements = this.GetElements(this.doc, BuiltInCategory.OST_FireAlarmDevices, typeof(FamilyInstance));
				this.PromptForFamilyInstancePlacement(this.familySymbol);
                List<ElementId> elements2 = this.GetElements(this.doc, BuiltInCategory.OST_FireAlarmDevices, typeof(FamilyInstance));
				List<ElementId> list = new List<ElementId>();
				foreach (ElementId item in elements2)
				{
					if (!elements.Contains(item))
					{
						list.Add(item);
					}
				}
				transaction = new Transaction(this.doc, "FireRandomLayout");
				transaction.Start();
				foreach (ElementId elementId in list)
				{
					Element element = this.doc.GetElement(elementId);
					if (element != null)
					{
						double level = fireRandomLayoutForm.Level;
						double radius = fireRandomLayoutForm.Radius;
						ElementParameter.SetLevel(element, level);
						this.SetParametersValue(element, level, radius);
						if (fireRandomLayoutForm.IsPreview)
						{
							FamilyInstance familyInstance = element as FamilyInstance;
							if (familyInstance != null)
							{
								double radius2 = UnitConvert.LengthToStd(radius);
								DetailCurve detailCurve = new AuxiliaryLineOperate().DrawRangLine(familyInstance, radius2, "FireCheck", 1);
								if (detailCurve != null)
								{
									new CreateProtectRange().RecordLastTimeTags(this.doc, element, new List<Element>
									{
										detailCurve
									});
								}
							}
						}
					}
				}
				transaction.Commit();
			}
			catch (Exception ex)
			{
				if (transaction != null && transaction.GetStatus() != TransactionStatus.Committed)
				{
					transaction.RollBack();
				}
				TaskDialog.Show("盈建科提示", ex.Message);
			}
			fireRandomLayoutForm.Close();
		}

		private bool PromptForFamilyInstancePlacement(FamilySymbol jigType)
		{
			bool result;
			try
			{
				this.uiDoc.PromptForFamilyInstancePlacement(jigType);
				result = true;
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		private void RectLayout(FireDetectorType type)
		{
			FireRectLayoutForm fireRectLayoutForm = new FireRectLayoutForm(this.doc, type);
			fireRectLayoutForm.Show(WindowHelper.HWndRevit);
			WindowHelper.SendMessageToWndRevit();
			for (;;)
			{
				XYZ xyz = null;
				XYZ xyz2 = null;
				try
				{
					xyz = this.uiDoc.Selection.PickPoint("请选取一点");
					LayoutEquipmentJig layoutEquipmentJig = new LayoutEquipmentJig(this.uiDoc, fireRectLayoutForm);
					xyz2 = layoutEquipmentJig.PickEndPoint(xyz, LayoutEquipmentJig.ELayoutType.eFireRect, "请选取对角点");
					layoutEquipmentJig.Dispose();
					if (xyz2 == null)
					{
						break;
					}
					if ((xyz2 - xyz).IsZeroLength())
					{
						TaskDialog.Show("盈建科提示", "选取的两点为同一点，请选取两个不同点。");
						continue;
					}
				}
				catch (Exception)
				{
					break;
				}
				double radius = fireRectLayoutForm.Radius;
				double maxSpace = fireRectLayoutForm.MaxSpace;
				double level = fireRectLayoutForm.Level;
				int linkLineWay = fireRectLayoutForm.LinkLineWay;
				int wireStyle = fireRectLayoutForm.WireStyle;
				bool isPreview = fireRectLayoutForm.IsPreview;
				List<List<XYZ>> insertPoints = this.GetInsertPoints(xyz, xyz2, maxSpace, linkLineWay);
				if (!this.IsEmptyPointSet(insertPoints))
				{
					TransactionGroup transactionGroup = new TransactionGroup(this.doc, "TransactionGroup");
					try
					{
						transactionGroup.Start();
						Transaction transaction = null;
						try
						{
							foreach (List<XYZ> list in insertPoints)
							{
								FamilyInstance startdevice = null;
								foreach (XYZ xyz3 in list)
								{
									transaction = new Transaction(this.doc, "FireRectLayout");
									transaction.Start();
									FamilyInstance familyInstance = YJKRevitTools.LayFamilySymbol(this.doc, xyz3, this.familySymbol, this.doc.ActiveView.GenLevel, 0.0);
									if (familyInstance == null)
									{
										throw new Exception("布置设备出错。");
									}
									ElementParameter.SetLevel(familyInstance, level);
									this.SetParametersValue(familyInstance, level, radius);
									if (isPreview)
									{
										double radius2 = UnitConvert.LengthToStd(radius);
										DetailCurve detailCurve = new AuxiliaryLineOperate().DrawRangLine(familyInstance, radius2, "FireCheck", 1);
										if (detailCurve != null)
										{
											new CreateProtectRange().RecordLastTimeTags(this.doc, familyInstance, new List<Element>
											{
												detailCurve
											});
										}
									}
									transaction.Commit();
									if (linkLineWay != 0)
									{
                                        NewConnectWire.CreateWire(this.doc, startdevice, familyInstance, (Autodesk.Revit.DB.Electrical.WiringType)wireStyle, null);
										startdevice = familyInstance;
									}
								}
							}
						}
						catch (Exception)
						{
							if (transaction != null && transaction.GetStatus() != TransactionStatus.Committed)
							{
								transaction.RollBack();
							}
							break;
						}
						transactionGroup.Assimilate();
						continue;
					}
					catch (Exception)
					{
						transactionGroup.RollBack();
						continue;
					}
					break;
				}
			}
			fireRectLayoutForm.Close();
		}

		private List<ElementId> GetElements(Document document, BuiltInCategory builtInCategory, Type type)
		{
			return new FilteredElementCollector(document).OfCategory(builtInCategory).OfClass(type).ToElementIds().ToList<ElementId>();
		}

		private List<List<XYZ>> GetInsertPoints(XYZ basePoint, XYZ diagonalPoint, double maxSpace, int LinkLineWay)
		{
			List<List<XYZ>> list = new List<List<XYZ>>();
			maxSpace = Math.Abs(UnitConvert.LengthToStd(maxSpace));
			XYZ xyz = new XYZ(diagonalPoint.X, basePoint.Y, diagonalPoint.Z);
			XYZ xyz2 = new XYZ(basePoint.X, diagonalPoint.Y, diagonalPoint.Z);
			double num = basePoint.DistanceTo(xyz);
			double num2 = basePoint.DistanceTo(xyz2);
			int num3;
			int num4;
			if (maxSpace <= 0.0)
			{
				num3 = 1;
				num4 = 1;
			}
			else
			{
				num3 = Convert.ToInt32(Math.Ceiling(num2 / maxSpace));
				num4 = Convert.ToInt32(Math.Ceiling(num / maxSpace));
			}
			double num5 = num / (double)num4;
			double num6 = num2 / (double)num3;
			if (LinkLineWay == 2)
			{
				for (int i = 0; i < num4; i++)
				{
					List<XYZ> list2 = new List<XYZ>();
					XYZ xyz3 = basePoint + num5 * (0.5 + (double)i) * (xyz - basePoint).Normalize();
					for (int j = 0; j < num3; j++)
					{
						XYZ item = xyz3 + num6 * (0.5 + (double)j) * (xyz2 - basePoint).Normalize();
						list2.Add(item);
					}
					list.Add(list2);
				}
			}
			else
			{
				for (int k = 0; k < num3; k++)
				{
					List<XYZ> list3 = new List<XYZ>();
					XYZ xyz4 = basePoint + num6 * (0.5 + (double)k) * (xyz2 - basePoint).Normalize();
					for (int l = 0; l < num4; l++)
					{
						XYZ item2 = xyz4 + num5 * (0.5 + (double)l) * (xyz - basePoint).Normalize();
						list3.Add(item2);
					}
					list.Add(list3);
				}
			}
			return list;
		}

		private bool IsEmptyPointSet(List<List<XYZ>> pointSet)
		{
			if (pointSet == null || pointSet.Count <= 0)
			{
				return true;
			}
			foreach (List<XYZ> list in pointSet)
			{
				if (list != null && list.Count > 0)
				{
					return false;
				}
			}
			return true;
		}

		private UIDocument uiDoc;

		private Document doc;

		private string familyFile = string.Empty;

		private FamilySymbol familySymbol;
	}
}
